#include<iostream>
#include"selectServer.hpp"
#include<memory>
#include"err.hpp"

using namespace std;
using namespace select_ns;

static void usage(std::string proc)
{
    std::cerr << "usage:\t\n" << proc << "port" << std::endl;
}

std::string transaction(const std::string& request)
{
    return request;
}
int main(int argc,char* argv[])
{
    if(argc != 2)
    {
        usage(argv[0]);
        exit(USAGE_ERR);
    }
    std::cout << "test: " << sizeof(fd_set)*8 << std::endl;// 128byte,位图结构*8
    unique_ptr<SelectServer> svr(new SelectServer(transaction));

    svr->initServer();

    svr->start();
    return 0;
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////

// select: IO = 等+拷贝
// select只负责等待，可以一次等待多个fd，select本身没有数据拷贝的能力，拷贝要read，write来完成

//////////////////////////////////////了解select基本概念和接口介绍/////////////////////////////////////////////


    // int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);全部都是：输入输出型参数
      // nfds：select要建设多个fd中值最大的fd+1
      // struct timeval *timeout：
      // nullprt:阻塞式
      // struct timeval timeout = {0,0}：非阻塞
      // struct timeval timeout = {5,0}：5s以内非阻塞式，超过5s，非阻塞返回一次
      // 返回值：>0 有几个文件符就绪了,==0 超时返回，<0 select调用失败

      // 1.select未来关心的事件，只有三类：a.读 b.写 c.异常 -- 对于任何一个fd，都是这三种
      // 2.fd_set：位图结果，表示文件标识符集合
// fd_set *readfds输入：表示用户告诉内核，你要帮我关系一下，我给你的集合中所有的fd的读事件 -- 哪些fd上的读时间内核你要关心
//                      比特位的位置，表示fd的数值，比特位的内容，表示是否关心
//                输出：内核告诉用户，你所关心的多个fd中，有哪些已经就绪了
//                     
// fd_set:既然式一种类型，必有大小，而且是固定的！所以，能够添加的fd的个数一定是有上限的！

//    void FD_CLR(int fd, fd_set *set);
//    int  FD_ISSET(int fd, fd_set *set);   判断当前套接字是否在位图结构中
//    void FD_SET(int fd, fd_set *set);     设置位图结构
//    void FD_ZERO(fd_set *set);            初始化位图结构

////////////////////////////////////////////////////////////////////////////////////////////////////////////

// 2.写代码tcpserver，只处理读取，只获取数据的server，便介绍select，server的更多细节
// listensock先交给select，能交给，listensock的链接就绪事件 == 读时间就绪

//////////////////////////////////////////////总结优缺点//////////////////////////////////////////////////////////////

// 1.select能够同时等待的文件fd是由上限的，除非重新改内核，否则无法解决(一个进程能打开65535个fd，select只能处理1024个fd)
// 2.必须借助第三方数组，来维护合法的fd
// 3.select大部分参数是输入输出型，调用select，要重新配置所有的fd，调用之后，我们还要检查更新所有的fd，这带来的就是遍历成本
// 4.select为什么第一个参数是最大fd+1呢？确定遍历范围 -- 内核层面
// 5.select 采用位图，用户->内核，内核->用户，来回进行数据拷贝，拷贝成本的问题